export type UnionToIntersection<T> = (
    T extends infer A ? (a: A) => void : never
) extends (a: infer P) => void
    ? P
    : never;

export type CreateTuple<
    L extends number,
    E = unknown,
    R extends E[] = []
> = R["length"] extends L ? R : CreateTuple<L, E, [...R, E]>;

export type Add<A extends number, B extends number> = [
    ...CreateTuple<A>,
    ...CreateTuple<B>
]["length"];

export type Unbox<
    A,
    Rec extends number = number,
    Cur extends unknown[] = [unknown]
> = (
    A extends () => infer R
        ? [true, R]
        : A extends (infer R)[]
        ? [true, R]
        : A extends Promise<infer R>
        ? [true, R]
        : [false, A]
) extends [infer B, infer T]
    ? B extends true
        ? Rec extends Cur["length"]
            ? T
            : Unbox<T, Rec, [...Cur, T]>
        : T
    : never;

export type Curring<F> = F extends (...args: infer Args) => infer R
    ? Args extends [infer Head, ...infer Tail]
        ? (arg: Head) => Curring<(...args: Tail) => R>
        : R
    : never;

export type Take<
    N extends number,
    T extends unknown[],
    R extends unknown[] = []
> = N extends R["length"]
    ? R
    : T extends [infer Head, ...infer Tail]
    ? Take<N, Tail, [...R, Head]>
    : R;

export type Drop<
    N extends number,
    T extends unknown[],
    Dropped extends unknown[] = []
> = N extends Dropped["length"]
    ? T
    : T extends [infer Head, ...infer Tail]
    ? Drop<N, Tail, [Head, ...Dropped]>
    : T;

export type GetRequired<T> = {
    [P in keyof T as Omit<T, P> extends T ? never : P]: T[P];
};

export type BaseType =
    | string
    | number
    | boolean
    | symbol
    | bigint
    | null
    | undefined;

export type ObjectKeyPaths<T, Path extends string = ""> = T extends BaseType
    ? never
    : keyof T extends infer K
    ? K extends keyof T
        ? K extends Exclude<BaseType, symbol>
            ? Path extends ""
                ? `${K}` | ObjectKeyPaths<T[K], `${K}`>
                : `${Path}.${K}` | ObjectKeyPaths<T[K], `${Path}.${K}`>
            : never
        : never
    : never;

export type TypedGet<
    T,
    K extends ObjectKeyPaths<T>
> = K extends `${infer Head}.${infer Rest}`
    ? Head extends keyof T
        ? Rest extends ObjectKeyPaths<T[Head]>
            ? TypedGet<T[Head], Rest>
            : never
        : never
    : T[K];
